﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UFrame;
using UnityEngine;

public class MinCSRef 
{
    public static bool isIgnoreCase;
    private static GameObject selectGO;
    public static BindingFlags bindSet = BindingFlags.Default | BindingFlags.Public | BindingFlags.Static |
                                 BindingFlags.NonPublic | BindingFlags.Instance;


    public static void SetIgnore()
    {
        if (isIgnoreCase)
        {
            MinCSRef.bindSet = BindingFlags.IgnoreCase | BindingFlags.Default | BindingFlags.Public | BindingFlags.Static |
                      BindingFlags.NonPublic | BindingFlags.Instance;
        }
        else
        {
            MinCSRef.bindSet = BindingFlags.Default | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic |
                      BindingFlags.Instance;
        }
    }

    public static void RunCode(GameObject go,string code)
    {
        bool isMethod = false;
        bool isField = false;

        string fieldName = string.Empty;
        string val = string.Empty;
        string[] fieldNameAry = null;

        if (go == null) 
        {
            fieldNameAry = code.Split('.');

            for(int i=0;i<fieldNameAry.Length;i++)
            {
                string goName = fieldNameAry[0];
                go = GameObject.Find(goName);
            }
        } 

        if (go == null)
            return;

        SetIgnore();
        var list = go.GetComponents<MonoBehaviour>();
        selectGO = go;
    

        if (code.Contains("="))
        {
            isField = true;
            var tempStr = code.Split('=');
            fieldName = tempStr[0].Trim();
            val = tempStr[1].TrimEnd(';').Trim();
        }
        else if (code.Contains("(") && code.Contains(")"))
        {
            isMethod = true;
        }
        else
        {
            fieldNameAry = code.Split('.');
            if (fieldNameAry.Length == 1)
            {
                RunFirst(list, fieldNameAry[0]);
                return;
            }

            MemberInfo mInfo = null;
            object yinyong = null;

            foreach (var monoItem in list)
            {
                if (monoItem.name == fieldNameAry[0])
                {
                    yinyong = monoItem;
                    break;
                }

                mInfo = SearchInfo(monoItem, fieldNameAry[0]);
                if (mInfo != null)
                {
                    yinyong = monoItem;
                    break;
                }
            }

            List<object> stack = new List<object>();
            stack.Add(yinyong);
            mInfo = LinkedSearch(stack, fieldNameAry, mInfo);

            if (mInfo != null)
            {
                PrintInfo(mInfo, stack[stack.Count - 1]);
                return;
            }
        }

        bool result = false;
        foreach (var item in list)
        {
            var type = item.GetType();
            if (isField)
            {
                //开始寻找字段
                MemberInfo mInfo = null;
                object yinyong = null;
                fieldNameAry = fieldName.Split('.');
                if (item.name == fieldNameAry[0])
                {
                    yinyong = item;
                }
                else
                {
                    mInfo = SearchInfo(item, fieldNameAry[0]);
                    if (mInfo == null)
                    {
                        continue;
                    }

                    yinyong = item;
                }


                List<object> stack = new List<object>();
                stack.Add(yinyong);
                mInfo = LinkedSearch(stack, fieldNameAry, mInfo);

                string fieldTypeName = string.Empty;
                if (mInfo is PropertyInfo)
                {
                    fieldTypeName = ((PropertyInfo)mInfo).PropertyType.Name;
                }

                if (mInfo is FieldInfo)
                {
                    fieldTypeName = ((FieldInfo)mInfo).FieldType.Name;
                }

                SetMemberInfo(mInfo, stack[stack.Count - 1], ConvertValue(fieldTypeName, val));
                Debug.Log("设置成功: " + val);
                result = true;
                break;
            }
            else if (isMethod)
            {
                AnalysisMethod(code);
                result = true;
                break;
                /*var methodInfo = type.GetMethod(fieldName, bindSet);
                if (methodInfo != null)
                {
                    methodInfo.Invoke(item, new object[] {val});
                    result = true;
                    Debug.Log("运行方法: " + methodInfo.Name);
                    break;
                }*/
            }
        }

        if (!result)
        {
            Debug.Log("设置失败");
        }
    }

    public static MemberInfo LinkedSearch(List<object> stack, string[] fieldNameAry, MemberInfo mInfo)
    {
        for (int i = 1, z = 0; i < fieldNameAry.Length; i++, z++)
        {
            string fieldName = fieldNameAry[i];
            if (mInfo is FieldInfo)
            {
                stack.Add(((FieldInfo)mInfo).GetValue(stack[z]));
                mInfo = SearchInfo(stack[z + 1], fieldName);
            }
            else if (mInfo is PropertyInfo)
            {
                stack.Add(((PropertyInfo)mInfo).GetValue(stack[z]));
                mInfo = SearchInfo(stack[z + 1], fieldName);
            }
        }

        return mInfo;
    }

    public static bool AnalysisMethod(string code)
    {
        code = code.TrimEnd(';');

        int leftK = code.IndexOf("(");
        if (leftK == -1)
        {
            return false;
        }

        string methodArgsS = code.Substring(leftK, code.Length - leftK);
        string methodName = code.Substring(0, leftK);
        var fieldNameAry = methodName.Split('.');

        var go = selectGO;
        var monoList = go.GetComponents<MonoBehaviour>();

        int index = 0;
        methodArgsS = methodArgsS.TrimStart('(');
        methodArgsS = methodArgsS.TrimEnd(')');
        var argsAry = methodArgsS.Split(',');
        object searchInfo = null;
        if (fieldNameAry.Length == 1)
        {
            object[] objAry = null;
            var objTypeAry = ConvertArgs(argsAry, out objAry);

            var info = RunFirst(monoList, fieldNameAry[0], objTypeAry, objAry);
            if (info != null)
            {
                return true;
            }
        }

        foreach (var item in fieldNameAry)
        {
        }

        return false;
    }

    public static MemberInfo SearchInfo(object monoItem, string name, params Type[] args)
    {
        Type t = null;
        if (monoItem is MemberInfo)
        {
            t = monoItem.GetType();
        }
        else
        {
            t = monoItem.GetType();
        }

        MethodInfo methodInfo = null;
        FieldInfo fieldInfo = null;
        PropertyInfo propertyInfo = null;

        if (args != null)
        {
            methodInfo = t.GetMethod(name, args);
        }
        else
        {
            methodInfo = t.GetMethod(name);
        }

        if (methodInfo != null)
        {
            return methodInfo;
        }

        fieldInfo = t.GetField(name, bindSet);
        if (fieldInfo != null)
        {
            return fieldInfo;
        }

        propertyInfo = t.GetProperty(name, bindSet);
        if (propertyInfo != null)
        {
            return propertyInfo;
        }

        return null;
    }

    public static void PrintInfo(MemberInfo info, object val, object[] argsObjAry = null)
    {
        if (info is FieldInfo)
        {
            Debug.Log("字段:" + ((FieldInfo)info).GetValue(val));
        }

        if (info is PropertyInfo)
        {
            Debug.Log("属性:" + ((PropertyInfo)info).GetValue(val));
        }

        if (info is MethodInfo)
        {
            ((MethodInfo)info).Invoke(val, argsObjAry);
            Debug.Log("方法: " + ((MethodInfo)info).Name);
        }
    }

    public static void SetMemberInfo(MemberInfo info, object obj, object val)
    {
        if (info is FieldInfo)
        {
            ((FieldInfo)info).SetValue(obj, val);
        }

        if (info is PropertyInfo)
        {
            ((PropertyInfo)info).SetValue(obj, val);
        }

        if (info is MethodInfo)
        {
            Debug.Log("错误SetMemberInfo方法: " + ((MethodInfo)info).Name);
        }
    }

    public static object RunFirst(MonoBehaviour[] monoList, string oneName, Type[] argsObjType = null,
        object[] argsObjAry = null)
    {
        oneName = oneName.Trim();
        object searchInfo = null;
        foreach (var monoItem in monoList)
        {
            searchInfo = SearchInfo(monoItem, oneName, argsObjType);

            if (searchInfo != null)
            {
                PrintInfo(searchInfo as MemberInfo, monoItem, argsObjAry);
                break;
            }
        }

        return searchInfo;
    }

    public static object ConvertValue(string fieldName, string val)
    {
        val = val.Trim();

        if (fieldName == "String")
        {
            return val;
        }

        if (fieldName == "Int32")
        {
            return Convert.ToInt32(val);
        }

        if (fieldName == "Int64")
        {
            return Convert.ToInt64(val);
        }

        if (fieldName == "Int16")
        {
            return Convert.ToInt16(val);
        }

        if (fieldName == "Single")
        {
            return Convert.ToSingle(val);
        }

        if (fieldName == "Double")
        {
            return Convert.ToDouble(val);
        }

        if (fieldName == "Boolean")
        {
            if (RegexTool.IsNumeric(val))
            {
                if (val == "0")
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }

            return Convert.ToBoolean(val);
        }

        if (fieldName == "Char")
        {
            val = val.Replace("'", "");
            val = val.Replace("‘", "");
            val = val.Replace("’", "");
            return Convert.ToChar(val);
        }

        if (fieldName == "Byte")
        {
            return Convert.ToByte(val);
        }

        return null;
    }

    public static Type[] ConvertArgs(string[] args, out object[] argObjAry)
    {
        argObjAry = new object[args.Length];
        Type[] argsObj = new Type[args.Length];

        for (int i = 0; i < args.Length; i++)
        {
            var arg = args[i];

            if (StringTool.IsBoolean(arg))
            {
                argObjAry[i] = Convert.ToBoolean(arg);
            }
            else if (RegexTool.IsNumericFloat(arg))
            {
                arg = arg.TrimEnd('f', 'F');
                argObjAry[i] = Convert.ToSingle(arg);
            }
            else if (RegexTool.IsNumericDouble(arg))
            {
                arg = arg.TrimEnd('d', 'D');
                argObjAry[i] = Convert.ToDouble(arg);
            }
            else if (RegexTool.IsNumericInteger(arg))
            {
                argObjAry[i] = Convert.ToInt32(arg);
            }
            else if (arg.StartsWith("'") && arg.EndsWith("'") && arg.Length == 3)
            {
                arg = arg.Substring(1, 1);
                argObjAry[i] = Convert.ToChar(arg);
            }
            else
            {
                arg = arg.Substring(1, arg.Length - 2);
                argObjAry[i] = arg;
            }

            argsObj[i] = argObjAry[i].GetType();
        }


        return argsObj;
    }
}
